package dlb.busstop.activities;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import org.json.JSONException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.text.format.DateFormat;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import dlb.busstop.R;
import dlb.busstop.data.Bus;
import dlb.busstop.data.BusStop;
import dlb.busstop.json.BusListGrabber;
import dlb.busstop.json.JSONParser;
import dlb.busstop.utils.BusListViewAdapter;

public class StopActivity extends BaseBusStopActivity {

        private static final String TAG = "StopActivity";

        private Menu mMenu;
        private BusListViewAdapter mBusListAdapter;
        private ListView mBusList;
        private TextView mDescriptionTv;
        private ProgressBar mLoading;
        private Button mNumberHeader;
        private Button mTimeHeader;
        private TextView mClock;
        
        private double mCurrLat;
        private double mCurrLong;

        private LatLng mCurrentLocation;

        private boolean mNumberAscceding;

        private BusStop mStop;
        private LoadBuListTask mBusListLoader;

        private GoogleMap mMap;
        private List<BusStop> mBusStops;
        private int mMapType;
        
        private HashMap<String, BusStop> mMarkerStop;

        @SuppressWarnings("unchecked")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_stop);
                Bundle extras = getIntent().getExtras();
                mStop= (BusStop) extras.getSerializable(STOP_KEY);
                mBusStops = (List<BusStop>) extras
                                .getSerializable(STOPS_KEY);
                mCurrLat = extras.getDouble(CURRENT_LOCATION_LAT,
                                DEFAUT_LOC);
                mCurrLong = extras.getDouble(CURRENT_LOCATION_LONG,
                                DEFAUT_LOC);
                if (mCurrLat != DEFAUT_LOC && mCurrLong != DEFAUT_LOC)
                        mCurrentLocation = new LatLng(mCurrLat, mCurrLong);
                
                initialiseViews();
                setListeners();
                if (savedInstanceState == null) {
                	mMapType = GoogleMap.MAP_TYPE_SATELLITE;
                        startLoadBuListTask();
                } else {
                	mMapType = savedInstanceState.getInt(MAP_TYPE_KEY);
                        NonConfigInstance instance = (NonConfigInstance) getLastCustomNonConfigurationInstance();
                        if (instance != null) {
                                if (instance.mBuses != null) {
                                        mBusListAdapter.setList(instance.mBuses);
                                }
                                if (instance.mBusLoader == null) {
                                        startLoadBuListTask();
                                } else {
                                        // i.e. asynctask is in progress don't do anything
                                        instance.mBusLoader.setStopActivity(this); // <- reset
                                }
                        } else {
                        }
                }
        }
        
        @Override
        protected void onRestart() {
                super.onRestart();
                startLoadBuListTask();
        }

        @Override
        protected void onResume() {
                super.onResume();
                mMap = getMap();
                if (mMap != null) {
                        setupMap();
                } else {
                }
        }

        private void setupMap() {
        	mMap.getUiSettings().setMyLocationButtonEnabled(true);
        	mMap.getUiSettings().setZoomControlsEnabled(false);
        	mMarkerStop.clear();
        	mMap.setMapType(mMapType);
                if (mBusStops != null) {
                        for (BusStop bs : mBusStops) {
                                MarkerOptions marker = new MarkerOptions().position(
                                                getLatLng(bs)).title(bs.getAddress());
                                if (bs.equals(mStop)) {
                                        marker.icon(BitmapDescriptorFactory
                                                        .fromResource(R.drawable.ic_bus_stop_selected)).title(bs.getDescription());
                                        mMarkerStop.put(mMap.addMarker(marker).getId(), bs);
                                        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                                                        getLatLng(bs), DEFAULT_ZOOM));
                                } else {
                                        marker.icon(BitmapDescriptorFactory
                                                        .fromResource(R.drawable.ic_bus_stop_other)).title(bs.getDescription());
                                        mMarkerStop.put(mMap.addMarker(marker).getId(), bs);
                                }
                        }
                        mMap.addMarker(new MarkerOptions()
                        .position(mCurrentLocation)
                        .icon(BitmapDescriptorFactory
                                        .fromResource(R.drawable.ic_my_location))
                        .title("Me"));
                } else {
                	mMap.addMarker(new MarkerOptions()
                    .position(mCurrentLocation)
                    .icon(BitmapDescriptorFactory
                                    .fromResource(R.drawable.ic_my_location))
                    .title("Me"));
                	mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                            mCurrentLocation, DEFAULT_ZOOM));
                }
                
                mMap.setOnMarkerClickListener(new OnMarkerClickListener() {
					
					@Override
					public boolean onMarkerClick(Marker marker) {
						
						if(mMarkerStop.get(marker.getId()) != null){
							mStop = mMarkerStop.get(marker.getId());
							startLoadBuListTask();
						}
						return false;
					}
				});
        }

        private LatLng getLatLng(BusStop bs) {
                return new LatLng(bs.getLatitude(), bs.getLongitude());
        }

        private GoogleMap getMap() {
                FragmentManager fm = getSupportFragmentManager();
                SupportMapFragment f = (SupportMapFragment) fm
                                .findFragmentById(R.id.map_fragment);
                return f.getMap();
        }

        private void initialiseViews() {
                mBusListAdapter = new BusListViewAdapter(this);
                mBusList = (ListView) findViewById(R.id.lvBuses);
                mDescriptionTv = (TextView) findViewById(R.id.tvDetDescription);
                mDescriptionTv.setText(mStop
                                .getDescription());
                mLoading = (ProgressBar) findViewById(R.id.pbStopLoading);
                mLoading.getIndeterminateDrawable().setColorFilter(0xFF0099cc,
                                android.graphics.PorterDuff.Mode.MULTIPLY);
                mNumberHeader = (Button) findViewById(R.id.btnNumberHeader);
                mTimeHeader = (Button) findViewById(R.id.btnTimeHeader);
                mClock = (TextView) findViewById(R.id.tvClock);
                mBusList.setAdapter(mBusListAdapter);
                
                mMarkerStop = new HashMap<String, BusStop>();
        }

        private void setListeners() {

                mNumberHeader.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                        	
                                mBusListAdapter.sortByNumber(mNumberAscceding);
                                mNumberAscceding = !mNumberAscceding;
                        }
                });

                mTimeHeader.setOnClickListener(new OnClickListener() {

                        @Override
                        public void onClick(View v) {
                                mBusListAdapter.sortByTime();
                        }
                });
        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
                mMenu = menu;
                getSupportMenuInflater().inflate(R.menu.stop_menu, mMenu);
                return super.onCreateOptionsMenu(mMenu);
        }

        @Override
        public boolean onMenuItemSelected(int featureId, MenuItem item) {
                switch (item.getItemId()) {
                case R.id.refresh_stop:
                    startLoadBuListTask();
                    break;
                case R.id.Hybrid:
                	setMapType(GoogleMap.MAP_TYPE_HYBRID);
                	break;
                case R.id.Satellite:
                	setMapType(GoogleMap.MAP_TYPE_SATELLITE);
                	break;
                case R.id.Normal:
                	setMapType(GoogleMap.MAP_TYPE_NORMAL);
                	break;
                case R.id.Terrain:
                	setMapType(GoogleMap.MAP_TYPE_TERRAIN);
                	break;
                default:
                        break;
                }
                return super.onMenuItemSelected(featureId, item);
        }

        private void setMapType(int mapType){
        	mMapType = mapType;
        	mMap.setMapType(mMapType);
        }
        
        private void startLoadBuListTask() {
                if (mBusListLoader == null) {
                        BusStop bs = mStop;
                        mBusListLoader = new LoadBuListTask(bs.getLocationId());
                        mBusListLoader.setStopActivity(this);
                        mBusListLoader.execute();
                }
        }
        
        @Override
        protected void onSaveInstanceState(Bundle outState) {
        	super.onSaveInstanceState(outState);
        	
        	outState.putInt(MAP_TYPE_KEY, mMapType);
        }

        @Override
        public Object onRetainCustomNonConfigurationInstance() {
                NonConfigInstance instance = new NonConfigInstance();
                instance.mBuses = mBusListAdapter.getList();
                instance.mBusLoader = mBusListLoader;
                return instance;
        }

        private void setLoading(boolean show) {
                if (show) {
                        mLoading.setVisibility(View.VISIBLE);
                } else {
                        mLoading.setVisibility(View.GONE);
                }
        }

        private static class LoadBuListTask extends
                        AsyncTask<Void, Void, List<Bus>> {

                private static final String TAG = "LoadBusListTask";

                private boolean mJsonError;
                private boolean mIOError;
                private StopActivity mStopActivity;
                private String mLocationId;

                public LoadBuListTask(String locationId) {
                        mLocationId = locationId;
                }

                private synchronized void setStopActivity(StopActivity stopActivity) {
                        mStopActivity = stopActivity;
                }

                @Override
                protected void onPreExecute() {
                        mStopActivity.setLoading(true);
                }

                @Override
                protected List<Bus> doInBackground(Void... params) {
                        JSONParser parser = JSONParser.getInstance();
                        BusListGrabber busListGrabber = BusListGrabber.getInstance(parser);
                        try {
                                return busListGrabber.grabBusList(mLocationId);
                        } catch (JSONException e) {
                                mJsonError = true;
                        } catch (IOException e) {
                                mIOError = true;
                        }
                        return null;
                }

                @Override
                protected void onPostExecute(List<Bus> buses) {
                        if (mIOError) {
                                mStopActivity.mDescriptionTv.setText(mStopActivity
                                                .getString(R.string.service_error_message));
                        } else if (mJsonError) {
                                mStopActivity.mDescriptionTv.setText(mStopActivity
                                                .getString(R.string.service_error_message));
                        } else {
                                if (buses != null) {
                                        mStopActivity.mBusListAdapter.setList(buses);
                                        mStopActivity.mClock.setVisibility(View.GONE);
                                } else {
                                        mStopActivity.mClock.setText(DateFormat.format("h:mm", new Date()));
                                        mStopActivity.mClock.setVisibility(View.VISIBLE);
                                }
                                mStopActivity.mDescriptionTv.setText(mStopActivity.mStop.getDescription());
                        }
                        mStopActivity.mBusListLoader = null;
                        // TODO: handle the case without internet
                        mStopActivity.setLoading(false);
                }
        }

        static class NonConfigInstance {
                List<Bus> mBuses;
                LoadBuListTask mBusLoader;
        }
}
